Q = [[1, 7, 8, 9],  # 业务1 走 1-7-8-9
     [2, 7, 9],  # 业务2 走 2-7-9
     [2, 7, 10],  # 业务3 走 2-7-10
     [3, 7, 10],  # 业务4 走 3-7-10
     [4, 7, 9],  # 业务5 走 4-7-9
     [4, 7, 10],  # 业务6 走 4-7-10
     [5, 8, 7, 9],  # 业务7 走 5-8-7-9
     [6, 7, 9],  # 业务8 走 6-7-9
     [6, 7, 10]]  # 业务9 走 6-7-10
import gurobipy as gp
from gurobipy import *
from gurobipy import GRB

try:

    # ①创建一个模型,gurobipy.Model('模型名')
    m = gp.Model("TTE_test")

    # ②设置参数变量   x = MODEL.addVars(20, 8, vtype=gurobipy.GRB.BINARY,'C')  Cij  i∈[0,20) j∈[0,8)
    C = m.addVars(range(1, 10), range(1, 10), vtype='C', name="C")

    M = m.addVar(lb=0, ub=gurobipy.GRB.INFINITY, vtype=GRB.SEMIINT, name='M')
    '''相当于一下设置了下面Z1-Z7，用Z[],表示下标'''
    Z = m.addVars(20, vtype=GRB.BINARY, name='Z')

    # 设置全局优化方向，所有目标的方向都是一致的，默认值为1表示求最小值，-1表示最大化，可以通过乘-1来调优化方向方向
    m.ModelSense = GRB.MINIMIZE

    # ③设置目标函数
    m.setObjectiveN(C[1, 7] + C[2, 7] + C[3, 7] + C[4, 7] + C[5, 7] + C[6, 7] + C[7, 7] + C[8, 7] + C[9, 7], index=0,
                    priority=2, abstol=0, reltol=0, name='obj1')
    m.setObjectiveN(C[1, 1] + C[2, 2] + C[3, 2] + C[4, 3] + C[5, 4] + C[6, 4] + C[7, 5] + C[8, 6] + C[9, 6], index=1,
                    priority=1, abstol=0, reltol=0, name='obj2')

    '''L1_7:表示在结点1到7这条链路上 简单分析，需要创建一个多维数组用来形成指定链路上的约束条件，'''
    # # ④设置约束条件 #第一个元素的[7,9]是指这条路的端结点，后面开始依次代表[业务号,帧长]
    # L1_7 = [ [1,7],[1, 1]                                 ]
    # L2_7 = [ [2,7],[2, 1], [3, 2]                         ]
    # L3_7 = [ [3,7],[4, 2]                                 ]
    # L4_7 = [ [4,7],[5, 3], [6, 3]                         ]
    # L5_7 = [ [5,7],[7, 4]                                 ]
    # L6_7 = [ [6,7],[8, 4], [9, 4]                         ]
    # L7_8 = [ [7,8],[1, 1], [2, 1], [5, 3], [7, 4], [8, 4] ]
    # L7_9 = [ [7,9],[3, 2], [4, 2], [6, 3], [9, 4]         ]
    #
    # k=0
    # def Add_Constrs(Ln_m):  # 参数是一个二维数组
    #     global k
    #     for i in range(1, len(Ln_m) - 1):
    #         for j in range(i + 1, len(Ln_m)):
    #             k += 1
    #             m.addConstr(C[Ln_m[i][0], Ln_m[0][0]] + Ln_m[i][1] <= C[Ln_m[j][0], Ln_m[0][0]] + Z[k] * M, '')
    #             m.addConstr(C[Ln_m[j][0], Ln_m[0][0]] + Ln_m[j][1] <= C[Ln_m[i][0], Ln_m[0][0]] + (1 - Z[k]) * M, '')
    #
    # Add_Constrs(L1_7)
    # Add_Constrs(L2_7)
    # Add_Constrs(L3_7)
    # Add_Constrs(L4_7)
    # Add_Constrs(L5_7)
    # Add_Constrs(L6_7)
    # Add_Constrs(L7_8)
    # Add_Constrs(L7_9)
    k=0
    L1_7 = [ [1, 1]]
    L2_7 = [ [2, 1], [3, 2]]
    L3_7 = [ [4, 2]]
    L4_7 = [ [5, 3], [6, 3]]
    L5_7 = [ [7, 4]]
    L6_7 = [ [8, 4], [9, 4]]
    L7_8 = [ [1, 1], [2, 1], [5, 3], [7, 4], [8, 4]]
    L7_9 = [ [3, 2], [4, 2], [6, 3], [9, 4]]
    for i in range(0, len(L1_7) - 1):
        for j in range(i + 1, len(L1_7)):
            k += 1
            m.addConstr(C[L1_7[i][0], 1] + L1_7[i][1] <= C[L1_7[j][0], 1] + Z[k] * M, '')
            m.addConstr(C[L1_7[j][0], 1] + L1_7[j][1] <= C[L1_7[i][0], 1] + (1 - Z[k]) * M, '')

    for i in range(len(L2_7) - 1):
        for j in range(i + 1, len(L2_7)):
            k += 1
            m.addConstr(C[L2_7[i][0], 2] + L2_7[i][1] <= C[L2_7[j][0], 2] + Z[k] * M, '')
            m.addConstr(C[L2_7[j][0], 2] + L2_7[j][1] <= C[L2_7[i][0], 2] + (1 - Z[k]) * M, '')

    for i in range(len(L3_7) - 1):
        for j in range(i + 1, len(L3_7)):
            k += 1
            m.addConstr(C[L3_7[i][0], 3] + L3_7[i][1] <= C[L3_7[j][0], 3] + Z[k] * M, '')
            m.addConstr(C[L3_7[j][0], 3] + L3_7[j][1] <= C[L3_7[i][0], 3] + (1 - Z[k]) * M, '')

    for i in range(len(L4_7) - 1):
        for j in range(i + 1, len(L4_7)):
            k += 1
            m.addConstr(C[L4_7[i][0], 4] + L4_7[i][1] <= C[L4_7[j][0], 4] + Z[k] * M, '')
            m.addConstr(C[L4_7[j][0], 4] + L4_7[j][1] <= C[L4_7[i][0], 4] + (1 - Z[k]) * M, '')

    for i in range(len(L5_7) - 1):
        for j in range(i + 1, len(L5_7)):
            k += 1
            m.addConstr(C[L5_7[i][0], 5] + L5_7[i][1] <= C[L5_7[j][0], 5] + Z[k] * M, '')
            m.addConstr(C[L5_7[j][0], 5] + L5_7[j][1] <= C[L5_7[i][0], 5] + (1 - Z[k]) * M, '')

    for i in range(len(L6_7) - 1):
        for j in range(i + 1, len(L6_7)):
            k += 1
            m.addConstr(C[L6_7[i][0], 6] + L6_7[i][1] <= C[L6_7[j][0], 6] + Z[k] * M, '')
            m.addConstr(C[L6_7[j][0], 6] + L6_7[j][1] <= C[L6_7[i][0], 6] + (1 - Z[k]) * M, '')

    for i in range(len(L7_8) - 1):
        for j in range(i + 1, len(L7_8)):
            k += 1
            m.addConstr(C[L7_8[i][0], 7] + L7_8[i][1] <= C[L7_8[j][0], 7] + Z[k] * M, '')
            m.addConstr(C[L7_8[j][0], 7] + L7_8[j][1] <= C[L7_8[i][0], 7] + (1 - Z[k]) * M, '')

    for i in range(len(L7_9) - 1):
        for j in range(i + 1, len(L7_9)):
            k += 1
            m.addConstr(C[L7_9[i][0], 7] + L7_9[i][1] <= C[L7_9[j][0], 7] + Z[k] * M, '')
            m.addConstr(C[L7_9[j][0], 7] + L7_9[j][1] <= C[L7_9[i][0], 7] + (1 - Z[k]) * M, '')

    # Q数组，每一行代表一个业务号的完整路径，每一行中的元素代表经过的端结点和交换机 譬如 1 3 4 5 表示业务1 经过 端结点1——结点3(交换机3)——结点4(交换机4)——端结点5
    Q = [   [1, 7, 8],      #业务1 走 1-7-8
            [2, 7, 8],      #业务2 走 2-7-8
            [2, 7, 9],      #业务3 走 2-7-9
            [3, 7, 9],      #业务4 走 3-7-9
            [4, 7, 8],      #业务5 走 4-7-8
            [4, 7, 9],      #业务6 走 4-7-9
            [5, 7, 8],      #业务7 走 5-7-8
            [6, 7, 8],      #业务8 走 6-7-8
            [6, 7, 9]   ]   #业务9 走 6-7-9

    F = [   [2.5, 2],       # F列表存放的是对应业务经过不同路径的时延损耗和（所有乱七八糟时间和）
            [2.5, 2],       # 业务2 路径2-7上的时延：2.5 , 在路径7-8上的时延：2 ,....一直到业务到达
            [2.5, 2],       # 业务3 路径2-7上的时延：2.5 , 在路径7-9上的时延：2 ,....一直到业务到达
            [2.5, 2],       # 业务4 路径3-7上的时延：2.5 , 在路径7-9上的时延：2 ,....一直到业务到达
            [2.5, 2],       # ......
            [2.5, 2],       # 现假设所有业务在各个路上的时延都一样，且都是经过一跳到达目的地
            [2.5, 2],       #  注意 ：
            [2.5, 2],       #    对于同一个业务一共经过n个端点，实际上整个路径上的约束条件一共只有n-2个，业务走过的每一段路都需要与其相邻的
            [2.5, 2],   ]   #    前一段路做短结点发送时刻的比较，直到倒数第二段路径的发送时刻+该段的时延一起与最后一段路径的发送时刻也约束完，
    '''对于这个F，因为我们只有一跳，且通过的端结点都是3个，我们只用的到每个业余第一段路径的时延 2 '''
    for i in range(0, len(Q)):
        for j in range(0, len(Q[i]) - 2):
            m.addConstr(C[i + 1, Q[i][j]] + F[i][j] <= C[i + 1, Q[i][j + 1]])  # （i+1） ：表示业务序号（行号索引从0开始）

    m.write('Test_9point2.lp')

    # ⑤开始求解
    m.optimize()  # m == gurobipy.Model

    '''循环遍历你设置的所有变量值'''
    for v in m.getVars():
        print('%s %g' % (v.varName, v.x))

    '''一下输出所有设置的变量值'''
    v = m.getVars()
    print(v)


    '''循环输出我想要的变量'''
    for i in range(1,9):
        print(C[i,7])

    print('\n---------------------------------------------')
    wangzai=C[2,7]
    print('wangzai=',C[2,7])

    '''显示设置的一个目标，如果设置了多个目标，返回优先级最大的'''
    print('Obj1: %g' % m.objVal)  # objVal：（优化后最优的目标结果值）

    # print(m.NumObj) 输出结果为2 ，因为我们设置了两个目标函数, 序号 index=0 ,index=1
    for i in range(m.NumObj):  # 可以使用NumObj属性查询(或修改)模型中的目标数量，它的值是目标函数的数量。遍历它，得到的是一个个index的值
        m.setParam(GRB.Param.ObjNumber, i)
        print('Obj%d = ' % (i + 1), m.ObjNVal)

    print('---------------------------------')
    print(m.getVarByName('M'))  #通过变量名来求设置变量的值，仅限于那些addval设置的单独变量
    print(m.getVarByName('Z'))


except gp.GurobiError as e:
    print('Error code ' + str(e.errno) + ': ' + str(e))

except AttributeError:  # 属性错误
    print('Encountered an attribute error')



